﻿using System.Collections.Generic;
using System.Windows.Media;
using Direct2D;
using Microsoft.WindowsAPICodePack.DirectX.Direct2D1;
using Microsoft.WindowsAPICodePack.DirectX.DirectWrite;
using SpectrumAnalyser.Controls.Wpf.ViewModels;
using DashStyle = Microsoft.WindowsAPICodePack.DirectX.Direct2D1.DashStyle;
using SolidColorBrush = Microsoft.WindowsAPICodePack.DirectX.Direct2D1.SolidColorBrush;

namespace SpectrumAnalyser.CustomControls.Wpf.Direct2D
{
    internal sealed class Graph2DScene : AnimatedScene
    {
        private IDictionary<Color, SolidColorBrush> _brushes;
        private SolidColorBrush _blackBrush;
        private TextFormat _textFormat;
        private readonly DWriteFactory _writeFactory;
        private readonly D2DFactory _d2DFactory;

        public IDictionary<Color, IList<SpectrumDataPointViewModel>> Source;
        private StrokeStyle _strokeStyle;
        public IList<Color> Colors { get; set; }

        public event OnRenderEventHandler OnRenderEvent;
        public delegate void OnRenderEventHandler(RenderTarget renderTarget, IDictionary<Color, SolidColorBrush> brushes, TextFormat textFormat, StrokeStyle d2DFactory);

        public Graph2DScene():base(100) // Will probably only be about 67 fps due to the limitations of the timer
        {
            _writeFactory = DWriteFactory.CreateFactory();
            _d2DFactory = D2DFactory.CreateFactory(D2DFactoryType.Multithreaded);   
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                _writeFactory.Dispose();
                _d2DFactory.Dispose();
            }
            base.Dispose(disposing);
        }

        protected override void OnCreateResources()
        {
            // We don't need to free any resources because the base class will
            // call OnFreeResources if necessary before calling this method.

            _brushes = new Dictionary<Color, SolidColorBrush>();
            foreach (var source in Colors)
            {
                _brushes.Add(source,
                             RenderTarget.CreateSolidColorBrush(
                                 new ColorF(new ColorI(source.R, source.G, source.B))));
            }

            _textFormat = _writeFactory.CreateTextFormat("Arial", 10);
            _strokeStyle = Factory.CreateStrokeStyle(new StrokeStyleProperties {DashOffset = 2, DashStyle = DashStyle.Dash});

            base.OnCreateResources(); // Call this last to start the animation
        }

        protected override void OnFreeResources()
        {
            base.OnFreeResources(); // Call this first to stop the animation

            if (_brushes != null)
            {
                foreach (var solidColorBrush in _brushes)
                {
                    solidColorBrush.Value.Dispose();
                }
                _brushes = null;
            }
            if (_blackBrush != null)
            {
                _blackBrush.Dispose();
                _blackBrush = null;
            }
            if (_textFormat != null)
            {
                _textFormat.Dispose();
                _textFormat = null;
            }if (_strokeStyle != null)
            {
                _strokeStyle.Dispose();
                _strokeStyle = null;
            }
        }

        protected override void OnRender()
        {
            // This draws the ellipse in red on a semi-transparent blue background
            RenderTarget.BeginDraw();
            RenderTarget.Clear(new ColorF(0, 0, 0, 0));

            OnRenderEvent(RenderTarget, _brushes, _textFormat, _strokeStyle);

            foreach (var source in Source)
            {
                for (int i = 1; i < source.Value.Count; i++)
                {
                    RenderTarget.DrawLine(
                        new Point2F((float)source.Value[i - 1].ViewPoint.X, (float)source.Value[i - 1].ViewPoint.Y),
                        new Point2F((float)source.Value[i].ViewPoint.X, (float)source.Value[i].ViewPoint.Y),
                        _brushes[source.Key], 1);
                }
            }

            // All done!
            RenderTarget.EndDraw();
        }
    }
}
